<?php
global $CFG;
require_once($CFG->dirroot . '/blocks/formal_langs/langs_src/tools/JLexPHP/jlex.php');
require_once($CFG->dirroot . '/blocks/formal_langs/tokens_base.php');
require_once($CFG->dirroot . '/blocks/formal_langs/langs_code/predefined/c_lang_parser.php');
%%

D	=	[0-9]
L	=	[a-zA-Z_]
H	=	[a-fA-F0-9]
E	=	[Ee][+-]?{D}+
FS	=	(f|F|l|L)
IS	=	(u|U|l|L)

%class c_lang_lexer
%function next_token
%char
%line
%state STRING COMMENT

%{
    private $debug_mode = false;    
    private $token_count = 0;

    public $errors = array();

    // buffer for accumulating string
    private $string_buffer;
    // begin and end line for position
    private $string_pos_bl, $string_pos_el;
    // begin and end column for position
    private $string_pos_bc, $string_pos_ec;

    private function return_token($type, $desc) {
        // create token object
        $res = new block_formal_langs_token_base(NULL, $type, $this->yytext(), $this->return_pos(), $this->token_count);
        $res->set_description($desc);
        // increase token count
        $this->token_count++;

        return $res;
    }

    private function return_pos() {
        $begin_line = $this->yyline;
        $begin_col = $this->yycol;

        if(strpos($this->yytext(), '\n')) {
            $lines = explode("\n", $this->yytext());
            $num_lines = count($lines);
            
            $end_line = $begin_line + $num_lines - 1;
            $end_col = strlen($lines[$num_lines -1]);
        } else {
            $end_line = $begin_line;
            $end_col = $begin_col + strlen($this->yytext());
        }
        
        $res = new block_formal_langs_node_position($begin_line, $end_line, $begin_col, $end_col);
        
        return $res;
    }

    private function return_string() {
        // create position object
        $pos = new block_formal_langs_node_position($this->string_pos_bl, $this->string_pos_el, $this->string_pos_bc, $this->string_pos_ec);
        // create token object
        $res = new block_formal_langs_token_base(NULL, c_lang_yyParser::STRING, $this->string_buffer, $pos, $this->token_count);
        $res->set_description("STRING");
        $this->token_count++;
        $this->string_buffer = '';

        return $res;
    }
%}

%%

<YYINITIAL> "/*"			{ 
    $this->yybegin(self::COMMENT);
}
<YYINITIAL> //[^\r\n]*      {}

<COMMENT>   "*/"            { 
    $this->yybegin(self::YYINITIAL); 
 }
<COMMENT>   (.|[\r\n])      {}

<YYINITIAL> #[^\r\n]*       { return $this->return_token(c_lang_yyParser::C_PRAGMA, "PRAGMA"); }

<YYINITIAL> "auto"     { return $this->return_token(c_lang_yyParser::C_AUTO, "AUTO"); }
<YYINITIAL> "break"    { return $this->return_token(c_lang_yyParser::C_BREAK, "BREAK"); }
<YYINITIAL> "case"     { return $this->return_token(c_lang_yyParser::C_CASE, "CASE"); }
<YYINITIAL> "char"     { return $this->return_token(c_lang_yyParser::C_CHAR, "CHAR"); }
<YYINITIAL> "const"    { return $this->return_token(c_lang_yyParser::C_CONST, "CONST"); }
<YYINITIAL> "continue" { return $this->return_token(c_lang_yyParser::C_CONTINUE, "CONTINUE"); }
<YYINITIAL> "default"  { return $this->return_token(c_lang_yyParser::C_DEFAULT, "DEFAULT"); }
<YYINITIAL> "do"       { return $this->return_token(c_lang_yyParser::C_DO, "DO"); }
<YYINITIAL> "double"   { return $this->return_token(c_lang_yyParser::C_DOUBLE, "DOUBLE"); }
<YYINITIAL> "else"     { return $this->return_token(c_lang_yyParser::C_ELSE, "ELSE"); }
<YYINITIAL> "enum"     { return $this->return_token(c_lang_yyParser::C_ENUM, "ENUM"); }
<YYINITIAL> "extern"   { return $this->return_token(c_lang_yyParser::C_EXTERN, "EXTERN"); }
<YYINITIAL> "float"    { return $this->return_token(c_lang_yyParser::C_FLOAT, "FLOAT"); }
<YYINITIAL> "for"      { return $this->return_token(c_lang_yyParser::C_FOR, "FOR"); }
<YYINITIAL> "goto"     { return $this->return_token(c_lang_yyParser::C_GOTO, "GOTO"); }
<YYINITIAL> "if"       { return $this->return_token(c_lang_yyParser::C_IF, "IF"); }
<YYINITIAL> "int"      { return $this->return_token(c_lang_yyParser::C_INT, "INT"); }
<YYINITIAL> "long"     { return $this->return_token(c_lang_yyParser::C_LONG, "LONG"); }
<YYINITIAL> "register" { return $this->return_token(c_lang_yyParser::C_REGISTER, "REGISTER"); }
<YYINITIAL> "return"   { return $this->return_token(c_lang_yyParser::C_RETURN, "RETURN"); }
<YYINITIAL> "short"    { return $this->return_token(c_lang_yyParser::C_SHORT, "SHORT"); }
<YYINITIAL> "signed"   { return $this->return_token(c_lang_yyParser::C_SIGNED, "SIGNED"); }
<YYINITIAL> "sizeof"   { return $this->return_token(c_lang_yyParser::C_SIZEOF, "SIZEOF"); }
<YYINITIAL> "static"   { return $this->return_token(c_lang_yyParser::C_STATIC, "STATIC"); }
<YYINITIAL> "struct"   { return $this->return_token(c_lang_yyParser::C_STRUCT, "STRUCT"); }
<YYINITIAL> "switch"   { return $this->return_token(c_lang_yyParser::C_SWITCH, "SWITCH"); }
<YYINITIAL> "typedef"  { return $this->return_token(c_lang_yyParser::C_TYPEDEF, "TYPEDEF"); }
<YYINITIAL> "union"    { return $this->return_token(c_lang_yyParser::C_UNION, "UNION"); }
<YYINITIAL> "unsigned" { return $this->return_token(c_lang_yyParser::C_UNSIGNED, "UNSIGNED"); }
<YYINITIAL> "void"     { return $this->return_token(c_lang_yyParser::C_VOID, "VOID"); }
<YYINITIAL> "volatile" { return $this->return_token(c_lang_yyParser::C_VOLATILE, "VOLATILE"); }
<YYINITIAL> "while"    { return $this->return_token(c_lang_yyParser::C_WHILE, "WHILE"); }

<YYINITIAL> {L}({L}|{D})*		{ return $this->return_token(c_lang_yyParser::C_IDENTIFIER, "IDENTIFIER"); }

<YYINITIAL> 0[xX]{H}+{IS}?		{ return $this->return_token(c_lang_yyParser::C_CONSTANT, "CONSTANT"); }
<YYINITIAL> 0{D}+{IS}?		        { return $this->return_token(c_lang_yyParser::C_CONSTANT, "CONSTANT"); }
<YYINITIAL> {D}+{IS}?		        { return $this->return_token(c_lang_yyParser::C_CONSTANT, "CONSTANT"); }
<YYINITIAL> L?\'(\\.|[^\\\'])+\'	{ return $this->return_token(c_lang_yyParser::C_CONSTANT, "CONSTANT"); }

<YYINITIAL> {D}+{E}{FS}?		{ return $this->return_token(c_lang_yyParser::C_CONSTANT, "CONSTANT"); }
<YYINITIAL> {D}*"."{D}+({E})?{FS}?	{ return $this->return_token(c_lang_yyParser::C_CONSTANT, "CONSTANT"); }
<YYINITIAL> {D}+"."{D}*({E})?{FS}?	{ return $this->return_token(c_lang_yyParser::C_CONSTANT, "CONSTANT"); }

<YYINITIAL> L?\"(\\.|[^\\\"])*\" 	{ return $this->return_token(c_lang_yyParser::C_STRING_LITERAL, "STRING_LITERAL"); }

<YYINITIAL> "..."      { return $this->return_token(c_lang_yyParser::C_ELLIPSIS, "ELLIPSIS"); }
<YYINITIAL> ">>="      { return $this->return_token(c_lang_yyParser::C_RIGHT_ASSIGN, "RIGHT_ASSIGN"); }
<YYINITIAL> "<<="      { return $this->return_token(c_lang_yyParser::C_LEFT_ASSIGN, "LEFT_ASSIGN"); }
<YYINITIAL> "+="       { return $this->return_token(c_lang_yyParser::C_ADD_ASSIGN, "ADD_ASSIGN"); }
<YYINITIAL> "-="       { return $this->return_token(c_lang_yyParser::C_SUB_ASSIGN, "SUB_ASSIGN"); }
<YYINITIAL> "*="       { return $this->return_token(c_lang_yyParser::C_MUL_ASSIGN, "MUL_ASSIGN"); }
<YYINITIAL> "/="       { return $this->return_token(c_lang_yyParser::C_DIV_ASSIGN, "DIV_ASSIGN"); }
<YYINITIAL> "%="       { return $this->return_token(c_lang_yyParser::C_MOD_ASSIGN, "MOD_ASSIGN"); }
<YYINITIAL> "&="       { return $this->return_token(c_lang_yyParser::C_AND_ASSIGN, "AND_ASSIGN"); }
<YYINITIAL> "^="       { return $this->return_token(c_lang_yyParser::C_XOR_ASSIGN, "XOR_ASSIGN"); }
<YYINITIAL> "|="       { return $this->return_token(c_lang_yyParser::C_OR_ASSIGN, "OR_ASSIGN"); }
<YYINITIAL> ">>"       { return $this->return_token(c_lang_yyParser::C_RIGHT_OP, "RIGHT_OP"); }
<YYINITIAL> "<<"       { return $this->return_token(c_lang_yyParser::C_LEFT_OP, "LEFT_OP"); }
<YYINITIAL> "++"       { return $this->return_token(c_lang_yyParser::C_INC_OP, "INC_OP"); }
<YYINITIAL> "--"       { return $this->return_token(c_lang_yyParser::C_DEC_OP, "DEC_OP"); }
<YYINITIAL> "->"       { return $this->return_token(c_lang_yyParser::C_PTR_OP, "PTR_OP"); }
<YYINITIAL> "&&"       { return $this->return_token(c_lang_yyParser::C_AND_OP, "AND_OP"); }
<YYINITIAL> "||"       { return $this->return_token(c_lang_yyParser::C_OR_OP, "OR_OP"); }
<YYINITIAL> "<="       { return $this->return_token(c_lang_yyParser::C_LE_OP, "LE_OP"); }
<YYINITIAL> ">="       { return $this->return_token(c_lang_yyParser::C_GE_OP, "GE_OP"); }
<YYINITIAL> "=="       { return $this->return_token(c_lang_yyParser::C_EQ_OP, "EQ_OP"); }
<YYINITIAL> "!="       { return $this->return_token(c_lang_yyParser::C_NE_OP, "NE_OP"); }
<YYINITIAL> ";"	       { return $this->return_token(c_lang_yyParser::C_SEMIC, "SEMIC"); }
<YYINITIAL> ("{"|"<%") { return $this->return_token(c_lang_yyParser::C_LCURLY, "LCURLY"); }
<YYINITIAL> ("}"|"%>") { return $this->return_token(c_lang_yyParser::C_RCURLY, "RCURLY"); }
<YYINITIAL> ","	       { return $this->return_token(c_lang_yyParser::C_COMMA, "COMMA"); }
<YYINITIAL> ":"	       { return $this->return_token(c_lang_yyParser::C_COLON, "COLON"); }
<YYINITIAL> "="	       { return $this->return_token(c_lang_yyParser::C_EQUALS, "EQUALS"); }
<YYINITIAL> "("	       { return $this->return_token(c_lang_yyParser::C_LPAREN, "LPAREN"); }
<YYINITIAL> ")"	       { return $this->return_token(c_lang_yyParser::C_RPAREN, "RPAREN"); }
<YYINITIAL> ("["|"<:") { return $this->return_token(c_lang_yyParser::C_LSQUARE, "LSQUARE"); }
<YYINITIAL> ("]"|":>") { return $this->return_token(c_lang_yyParser::C_RSQUARE, "RSQUARE"); }
<YYINITIAL> "."	       { return $this->return_token(c_lang_yyParser::C_PERIOD, "PERIOD"); }
<YYINITIAL> "&"	       { return $this->return_token(c_lang_yyParser::C_AMP, "AMP"); }
<YYINITIAL> "!"	       { return $this->return_token(c_lang_yyParser::C_EXCLAM, "EXCLAM"); }
<YYINITIAL> "~"	       { return $this->return_token(c_lang_yyParser::C_TILDE, "TILDE"); }
<YYINITIAL> "-"	       { return $this->return_token(c_lang_yyParser::C_MINUS, "MINUS"); }
<YYINITIAL> "+"	       { return $this->return_token(c_lang_yyParser::C_PLUS, "PLUS"); }
<YYINITIAL> "*"	       { return $this->return_token(c_lang_yyParser::C_STAR, "STAR"); }
<YYINITIAL> "/"	       { return $this->return_token(c_lang_yyParser::C_SLASH, "SLASH"); }
<YYINITIAL> "%"	       { return $this->return_token(c_lang_yyParser::C_PERCENT, "PERCENT"); }
<YYINITIAL> "<"	       { return $this->return_token(c_lang_yyParser::C_LANGLE, "LANGLE"); }
<YYINITIAL> ">"	       { return $this->return_token(c_lang_yyParser::C_RANGLE, "RANGLE"); }
<YYINITIAL> "^"	       { return $this->return_token(c_lang_yyParser::C_CARET, "CARET"); }
<YYINITIAL> "|"	       { return $this->return_token(c_lang_yyParser::C_PIPE, "PIPE"); }
<YYINITIAL> "?"	       { return $this->return_token(c_lang_yyParser::C_QUESTION, "QUESTION"); }

<YYINITIAL> [ \t\v\n\f] { }

. { /* process bad input */
    $error = array();
    $error['line'] = $this->yyline;
    $error['column'] = $this->yycol;
    $error['input'] = $this->yytext();

    $this->errors[] = $error;
}
